<?php
	/**
	 * Directory class represents an existing directory in the filesystem.
	 * @author IMP
	 */
	
	class Dir {
		protected $dirPath;
		
		public function __construct($path2dir, $create = false, $mod = 0777){
			if(is_dir($path2dir) || $create){
				if($create && !is_dir($path2dir)) mkdir($path2dir, $mod, true);
				$this->dirPath = $path2dir;
			}else{
				throw new DirectoryNotFoundException($path2dir);
			}
		}
		
		public function __toString(){
			return $this->getAbsolutePath();
		}
		
		public function getPath($sub = null){
			return $this->dirPath . ($sub != null ? DS . $sub : '');
		}
		
		public function getAbsolutePath($sub = null){
			return realpath($this->getPath()) . ($sub != null ? DS . $sub : '');
		}
		
		public function getAbsoluteDirectory(){
			 return new self($this->getAbsolutePath());
		}
		
		public function hasReadPermission(){
			return posix_access($this->getAbsoluteDirectory(), POSIX_R_OK);
		}
		
		public function hasWritePermission(){
			return posix_access($this->getAbsoluteDirectory(), POSIX_F_OK);
		}
		
		public function hasExecutePermission(){
			return posix_access($this->getAbsoluteDirectory(), POSIX_X_OK);
		}
		
		public function listDirectories($pattern = '*', $all = false){
			$dirs = array();
			
			foreach(glob($this->getPath() . '/' . $pattern, GLOB_ONLYDIR) as $d){
				$d = new self($d);
				$dirs[] = $d;
				if($all) $dirs = array_merge($dirs, $d->listDirectories($pattern, $all));
			}
			
			return $dirs;
		}
		
		public function listFiles($pattern = '*'){
			$files = array();
			
			foreach(glob($this->getPath() . '/' . $pattern) as $d){
				if(is_file($d)) $files[] = new File($d);
			}
			
			return $files;
		}
		
		public function search($pattern){
			$found = $this->listFiles($pattern);
			foreach($this->listDirectories('*', true) as $d){
				$found = array_merge($found, $d->listFiles($pattern));
			}
			
			return $found;
		}
		
		public function getParent(){
			return new self(dirname($this->getAbsolutePath()));
		}
		
		public function contains($s){
			if($s instanceof Dir || $s instanceof File){
				$p1 = $s->getAbsolutePath();
				if(strlen($p1) > strlen($this->getAbsolutePath())){
					return substr($p1, 0, strlen($this->getAbsolutePath())) == $this->getAbsolutePath();
				}else return false;
			}else{
				throw new ParameterException('$s', array('Dir', 'File'), $s);
			}
		}
		
		public static function exists($path2file){
			return is_dir($path2file);
		}
		
		public function getRelativePath($s){
			if($s instanceof Dir || $s instanceof File){
				if($this->contains($s)){
					$d = $this->getAbsolutePath();
					$ds = $s->getAbsolutePath();
					
					return trim(substr($ds, strlen($d)), DS);
				}else{
					throw new Exception('Given file/directory is no child of this directory.');
				}
			}else{
				throw new ParameterException('$s', array('Dir', 'File'), $s);
			}
		}
	}
?>